﻿using System;
using System.Collections.Generic;

namespace MeTool
{
    /// <summary>用于承载返回的执行结果的接口</summary>
    public interface IResultBase
    {
        /// <summary>错误说明,当此值为空时通常表示没有发生错误</summary>
        string ErrText { get; set; }
    }

    /// <summary>
    /// 此类用于承载返回的执行结果
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class Result<T> : IResultBase
    {
        /// <summary>此类用于承载返回的执行结果</summary>
        public Result()
        {
            ErrText = "";
            Message = "";
        }

        /// <summary>错误说明,当此值为空时通常表示没有发生错误</summary>
        public string ErrText { get; set; }

        /// <summary>返回结果的内容</summary>
        public T Item { get; set; }

        /// <summary>附加消息</summary>
        public string Message { get; set; }

        /// <summary>
        /// 数据提供方调用,当执行失败需要返回错误时调用此方法
        /// </summary>
        /// <param name="errorText"></param>
        /// <returns></returns>
        public Result<T> ToError(string errorText)
        {
            ErrText = errorText;
            Item = default;
            return this;
        }

        /// <summary>
        /// 数据提供方调用,当执行失败需要返回错误时调用此方法
        /// </summary>
        /// <param name="errorResult"></param>
        /// <returns></returns>
        public Result<T> ToError(IResultBase errorResult)
        {
            ErrText = errorResult.ErrText;
            Item = default;
            return this;
        }

        /// <summary>
        /// 数据提供方调用,当执行成功需要返回数据时调用此方法
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        public Result<T> ToOK(T item)
        {
            Item = item;
            return this;
        }

        /// <summary>
        /// 按执行结果的规则设置对象的状态. 规则如下: theExecutedResult="1" 时让Item返回theItem,否则设置为错误说明且Item返回null
        /// </summary>
        /// <param name="executedResult"></param>
        /// <param name="getItemAction"></param>
        /// <returns></returns>
        public Result<T> ToResult(string executedResult, Func<T> getItemAction)
        {
            return executedResult == "1" ? ToOK(getItemAction()) : ToError(executedResult);
        }

        /// <summary>
        /// ErrText有值时,执行一个处理错误的委托(ErrText无值时不执行). 之后返回结果包装的对象
        /// <para>注意: 这里的判断是 ErrText 不为 ""</para>
        /// </summary>
        /// <param name="errorAction">参数为错误说明</param>
        /// <returns></returns>
        public T WhenErr(Action<string> errorAction)
        {
            if (ErrText.IsNotEmpty()) errorAction(ErrText);
            return Item;
        }

        /// <summary>
        /// ErrText有值时,执行一个处理错误的委托(ErrText无值时不执行),并返回True. setvalue用来返回结果包装的对象.
        /// <para>注意: 返回 True 表示 ErrText 不为 ""</para>
        /// </summary>
        /// <param name="errorAction">参数为错误说明</param>
        /// <param name="setValue"></param>
        /// <returns></returns>
        public bool WhenErr(Action<string> errorAction, out T setValue)
        {
            if (ErrText.IsNotEmpty()) errorAction(ErrText);
            setValue = Item;
            return ErrText.IsNotEmpty();
        }

        /// <summary>
        /// ErrText不为1时,执行一个处理错误的委托(ErrText==1时不执行). 之后返回结果包装的对象
        /// <para>注意: 这里的判断是 ErrText 不为 "1"</para>
        /// </summary>
        /// <param name="errorAction">当ErrText不为1时,此委托被调用,ErrText=1时忽略此委托</param>
        /// <returns></returns>
        public T WhenFail(Action<string> errorAction)
        {
            if (ErrText != "1") errorAction(ErrText);
            return Item;
        }

        /// <summary>
        /// ErrText不为1时,执行一个处理错误的委托(ErrText=1时不执行),并返回True. setvalue用来返回结果包装的对象.
        /// <para>注意: 返回 True 表示 ErrText 不为 1</para>
        /// </summary>
        /// <param name="errorAction"></param>
        /// <param name="setValue"></param>
        /// <returns></returns>
        public bool WhenFail(Action<string> errorAction, out T setValue)
        {
            if (ErrText != "1") errorAction(ErrText);
            setValue = Item;
            return ErrText != "1";
        }

        /// <summary>
        /// 当Item为Null时,执行一个指定的委托. 之后返回结果包装的对象
        /// <para>Item为Null时,有两种可能,执行出错或者没有符合的内容,这时可以通过ErrText判断</para>
        /// </summary>
        /// <param name="errorAction">当Item为Null时,此委托被调用,Item不为Null时此委托不被执行. 委托的参数为ErrText</param>
        /// <returns></returns>
        public T WhenNull(Action<string> errorAction)
        {
            if (Item == null) errorAction(ErrText);
            return Item;
        }

        /// <summary>
        /// 当Item为Null时,执行一个指定的委托,并返回True. 用setvalue返回结果包装的对象.
        /// <para>注意: 返回 True 表示结果为 Null</para>
        /// </summary>
        /// <param name="theAction"></param>
        /// <param name="setvalue"></param>
        /// <returns></returns>
        public bool WhenNull(Action<string> errorAction, out T setValue)
        {
            if (Item == null) errorAction(ErrText);
            setValue = Item;
            return Item == null;
        }

        /// <summary>
        /// 把此对象转换成另一个泛型的Result
        /// </summary>
        /// <typeparam name="T2"></typeparam>
        /// <param name="convertFunc"></param>
        /// <returns></returns>
        public Result<T2> Convert<T2>(Func<T, T2> convertFunc)
        {
            return new Result<T2>
            {
                ErrText = ErrText,
                Item = convertFunc(Item),
                Message = Message
            };
        }
    }

    /// <summary>
    /// 本类用于承载返回的执行结果,且结果是一个泛型List
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class ResultList<T> : IResultBase
    {
        /// <summary>错误说明,当此值为空时通常表示没有发生错误</summary>
        public string ErrText { get; set; } = "";

        /// <summary>返回结果的内容</summary>
        public List<T> Item { get; set; } = new List<T>();

        /// <summary>附加消息</summary>
        public string Message { get; set; } = "";

        /// <summary>
        /// 数据提供方调用,当执行失败需要返回错误时调用此方法
        /// </summary>
        /// <param name="errorText"></param>
        /// <returns></returns>
        public ResultList<T> ToError(string errorText)
        {
            ErrText = errorText;
            Item = null;
            return this;
        }

        /// <summary>
        /// 数据提供方调用,当执行失败需要返回错误时调用此方法
        /// </summary>
        /// <param name="errorResult"></param>
        /// <returns></returns>
        public ResultList<T> ToError(IResultBase errorResult)
        {
            ErrText = errorResult.ErrText;
            Item = default;
            return this;
        }

        /// <summary>
        /// 数据提供方调用,当执行成功需要返回数据时调用此方法
        /// </summary>
        /// <param name="list"></param>
        /// <returns></returns>
        public ResultList<T> ToOK(List<T> list)
        {
            Item = list;
            return this;
        }

        /// <summary>
        /// 按执行结果的规则设置对象的状态. 规则如下: theExecutedResult = "1" 时让Item返回 theItem, 否则设置为错误说明且 Item 返回 null
        /// </summary>
        /// <param name="executedResult"></param>
        /// <param name="list"></param>
        /// <returns></returns>
        public ResultList<T> ToResult(string executedResult, List<T> list)
        {
            return executedResult == "1" ? ToOK(list) : ToError(executedResult);
        }

        /// <summary>
        /// ErrText有值时,执行一个处理错误的委托 ( ErrText = "" 时不执行 ). 之后返回结果包装的对象
        /// <para>注意: 这里的判断是 ErrText 不为 ""</para>
        /// </summary>
        /// <param name="errorAction">当 ErrText 不为 "" 时,此委托被调用</param>
        /// <returns></returns>
        public List<T> WhenErr(Action<string> errorAction)
        {
            if (ErrText.IsNotEmpty()) errorAction(ErrText);
            return Item;
        }

        /// <summary>
        /// ErrText不为1时,执行一个处理错误的委托 ( ErrText = "1" 时不执行 ). 之后返回结果包装的对象
        /// <para>注意: 这里的判断是 ErrText 不为 "1"</para>
        /// </summary>
        /// <param name="errorAction">当ErrText不为1时,此委托被调用,ErrText=1时忽略此委托</param>
        /// <returns></returns>
        public List<T> WhenFail(Action<string> errorAction)
        {
            if (ErrText != "1") errorAction(ErrText);
            return Item;
        }

        /// <summary>
        /// 当Item为Null时,执行一个指定的委托. 之后返回结果包装的对象
        /// </summary>
        /// <param name="errorAction">当Item为Null时,此委托被调用,Item不为Null时此委托不被执行. 委托的参数为ErrText</param>
        /// <returns></returns>
        public List<T> WhenNull(Action<string> errorAction)
        {
            if (Item == null) errorAction(ErrText);
            return Item;
        }

        /// <summary>
        /// 把此对象转换成另一个泛型的Result
        /// </summary>
        /// <typeparam name="T2"></typeparam>
        /// <param name="convertFunc"></param>
        /// <returns></returns>
        public ResultList<T2> Convert<T2>(Func<T, T2> convertFunc)
        {
            return new ResultList<T2>
            {
                ErrText = ErrText,
                Item = Item.ConvertAll(i => convertFunc(i)),
                Message = Message
            };
        }
    }

    /// <summary>
    /// 用于包装返回值
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class CValue<T>
    {
        /// <summary>
        /// 返回的数据
        /// </summary>
        public T d;

        /// <summary>
        /// 支持直接指定数据, 方便代码编写
        /// </summary>
        /// <param name="value"></param>
        public static implicit operator CValue<T>(T value)
        {
            return new CValue<T> { d = value };
        }
    }
}
